#pragma once
#include <iostream>
#include <string>
#include <semaphore.h>
#include <vector>

using namespace std;

const int gCap = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(int cap = gCap) : ringqueue_(cap), pIndex_(0), cIndex_(0)
    {
        // 生产者
        sem_init(&roomSem_, 0, ringqueue_.size());
        // 消费者
        sem_init(&dataSem_, 0, 0);

        pthread_mutex_init(&pmutex_, nullptr);
        pthread_mutex_init(&cmutex_, nullptr);
    }

    ~RingQueue()
    {
        sem_destroy(&roomSem_);
        sem_destroy(&dataSem_);

        pthread_mutex_destroy(&pmutex_);
        pthread_mutex_destroy(&cmutex_);
    }

    void push(const T &in)
    {
        // pthread_mutex_lock(&pmutex_); // 将锁加在这里会导致信号量无法被多次申请

        sem_wait(&roomSem_);
        pthread_mutex_lock(&pmutex_);

        ringqueue_[pIndex_] = in;
        pIndex_++;
        pIndex_ %= ringqueue_.size();

        pthread_mutex_unlock(&pmutex_);
        sem_post(&dataSem_);
    }

    T pop()
    {
        sem_wait(&dataSem_);
        pthread_mutex_lock(&cmutex_);

        T temp = ringqueue_[cIndex_];
        cIndex_++;
        cIndex_ %= ringqueue_.size();

        pthread_mutex_unlock(&cmutex_);
        sem_post(&roomSem_);
        return temp;
    }

private:
    vector<T> ringqueue_; // 环形队列
    sem_t roomSem_;       // 衡量空间计数器，producer
    sem_t dataSem_;       // 衡量数据计数器，consumer
    uint32_t pIndex_;     // 当前生产者写入的位置,如果是多线程，pIndex_也是临界资源
    uint32_t cIndex_;     // 当前消费者读取的位置，如果是多线程，cIndex_也是临界资源

    pthread_mutex_t pmutex_;
    pthread_mutex_t cmutex_;
};